export const isEmpty = function (val: { message?: any; length?: any; size?: any; } | null) {
  // null or undefined
  if (val == null) return true;
  if (typeof val === 'boolean') return false;
  if (typeof val === 'number') return !val;
  if (val instanceof Error) return val.message === '';
  switch (Object.prototype.toString.call(val)) {
    // String or Array
    case '[object String]':
    case '[object Array]':
      return !val.length;
    // Map or Set or File
    case '[object File]':
    case '[object Map]':
    case '[object Set]': {
      return !val.size;
    }
    // Plain Object
    case '[object Object]': {
      return !Object.keys(val).length;
    }
  }
  return false;
};

/*
对Date的扩展，将 Date 转化为指定格式的String
月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q)可以用1-2个占位符
年(y)可以用1-4个占位符，毫秒(S)只能用1个占位符号(是1-3为的数字)
例子：
(new Date()).Format("yyyy-MM-dd hh:mm:ss.S")	==> 2006-07-02 08:09:04.423
(new Date()).Format("yyyy-M-d h:m:s.S")			==> 2006-7-2 8:9:4.18
*/
// @ts-ignore
Date.prototype.format = function (fmt: string) {
  const o = {
    "y+": this.getFullYear(),
    "M+": this.getMonth() + 1,
    "d+": this.getDate(),
    "H+": this.getHours(),
    "m+": this.getMinutes(),
    "s+": this.getSeconds(),
    "S+": this.getMilliseconds(),
    "q+": Math.floor(this.getMonth() / 3) + 1,
    "h+": (() => {
      const hour = this.getHours() % 12;
      return hour == 0 ? 12 : hour;
    })(),
    "E+": (() => {
      const week = { "0": "Sunday", "1": "Monday", "2": "Tuesday", "3": "Wednesday", "4": "Thursday", "5": "Friday", "6": "Saturday" };
      // @ts-ignore
      return week[this.getDay() + ""];
    })(),
    "x1": (() => {
      const week = { "0": "周日", "1": "周一", "2": "周二", "3": "周三", "4": "周四", "5": "周五", "6": "周六" };
      // @ts-ignore
      return week[this.getDay() + ""];
    })(),
    "x2": (() => {
      const hour = ["凌晨", "早上", "下午", "晚上"];
      const h = this.getHours();
      if (h === 12) return "中午";
      // @ts-ignore
      return hour[parseInt(h / 6)];
    })(),
  }
  for (var k in o) {
    if (new RegExp("(" + k + ")", "g").test(fmt)) {
      const len = RegExp.$1.length;
      // @ts-ignore
      fmt = fmt.replace(RegExp.$1, len == 1 ? o[k] : ("00" + o[k]).substr(-len));
    }
  }
  return fmt;
}
// @ts-ignore
Date.prototype.toWeiXinString = function (shortShow = true) {
  let str;
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
  const monday = new Date(today);
  monday.setDate(today.getDate() - (today.getDay() ? today.getDay() - 1 : 6));
  //注意：date初始化默认是按本地时间初始的，但打印默认却是按GMT时间打印的，也就是说打印出的不是本地现在的时间
  //LocaleString的打印也有点问题，"0点"会被打印为"上午12点"
  if (this.getTime() > today.getTime()) {
    // @ts-ignore
    str = this.format("HH:ss");
  } else if (this.getTime() > yesterday.getTime()) {
    str = "昨天";
  } else if (this.getTime() > monday.getTime()) {
    const week = { "0": "周日", "1": "周一", "2": "周二", "3": "周三", "4": "周四", "5": "周五", "6": "周六" };
    // @ts-ignore
    str = week[this.getDay() + ""];
  } else {
    // @ts-ignore
    str = this.format("yy/MM/dd");
  }
  if (!shortShow && this.getTime() <= today.getTime()) {
    // @ts-ignore
    str += this.format("HH:mm:ss");
  }
  return str;
};

export const getLatestDays = (days = 20) => {
  let arr = [];
  const now = new Date();
  for (let i = 0; i < days; i++) {
    const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() - i);
    // @ts-ignore
    arr.push(d.format("dd"));
  }
  return arr.reverse();
}
// @ts-ignore
export const formatChatDialogueTime = function (time) {
  // @ts-ignore
  return new Date(Number(time)).toWeiXinString(true);
};
// @ts-ignore
export const formatChatMainWindowTime = function (time) {
  // @ts-ignore
  return new Date(Number(time)).toWeiXinString(false);
};
// @ts-ignore
export const formatNormalTime = (time) => {
  if (!time || !Number(time)) return time;
  // @ts-ignore
  return new Date(Number(time)).format('yyyy-MM-dd hh:mm:ss');
}

export const jsonParse = function (str: string) {
  try {
    return JSON.parse(str)
  } catch (e) {
    return {}
  }
}

export const jsonClone = (obj: any) => {
  try {
    return JSON.parse(JSON.stringify(obj))
  } catch (e) {
    return {}
  }
}

export const WS = {
  url: null,
  token: null,
  callback: null,
  socket: null,//socket对象
  pptt: null,//心跳机制的延时函数
  isCloseBySelf: false,//是否客户端主动关闭
  lockReconnect: false,//避免重复连接
  onConnectOk: null,//连接成功回调
  onConnecting: null,//连接中回调
  onConnectError: null,//连接错误回调
  // @ts-ignore
  connectServer(url, token, callback) {
    let _this = this;
    _this.url = url;
    _this.token = token;
    _this.callback = callback;
    _this.isCloseBySelf = false;
    try {
      // @ts-ignore
      _this.socket = new WebSocket(url + '?token=' + token);
      _this.initSocket(callback);
    } catch (e) {
      _this.reconnect();
    }
    return _this;
  },
  // @ts-ignore
  initSocket(callback) {
    let _this = this;
    // @ts-ignore
    _this.socket.onopen = function () {
      console.log('连接成功')
      // @ts-ignore
      typeof _this.onConnectOk === 'function' && _this.onConnectOk()
      // @ts-ignore
      _this.socket.send('ping');
    };
    // @ts-ignore
    _this.socket.onmessage = function (event) {
      if ('pong' === event.data) {//发送字符串ping,服务器会返回pong,间隔30s做心跳
        // @ts-ignore
        _this.pptt = setTimeout(function () {
          // @ts-ignore
          _this.socket.send('ping');
        }, 30000);
        return;
      }
      if (callback) {
        console.log('type of callback', typeof callback);
        callback(event.data);
      }
    };
    // @ts-ignore
    _this.socket.onclose = function (e) {
      //当客户端收到服务端发送的关闭连接请求时，触发onclose事件
      // @ts-ignore
      _this.socket.close();
      console.log("连接关闭了", e);
      // @ts-ignore
      typeof _this.onConnectError === 'function' && _this.onConnectError()
      _this.reconnect();
    };
    // @ts-ignore
    _this.socket.onerror = function (e) {
      //如果出现连接、处理、接收、发送数据失败的时候触发onerror事件
      console.log('出现异常', e);
      // @ts-ignore
      typeof _this.onConnectError === 'function' && _this.onConnectError()
      _this.reconnect();
    };
  },
  reconnect() {
    let _this = this;
    if (_this.lockReconnect) {       // 是否已经执行重连
      return;
    }
    if (_this.isCloseBySelf) {       // 是否主动关闭的
      return;
    }
    _this.pptt && clearTimeout(_this.pptt);
    _this.lockReconnect = true;//没连接上会一直重连，设置延迟避免请求过多
    console.log('连接已断开,重新连接', _this.url, _this.token);
    // @ts-ignore
    typeof _this.onConnecting === 'function' && _this.onConnecting()
    setTimeout(function () {
      _this.lockReconnect = false;
      _this.connectServer(_this.url, _this.token, _this.callback);
    }, 5000);
  },
  disconnectWebSocket() {
    let _this = this;
    if (_this.socket) {
      console.log('客户端主动关闭连接', _this.url, _this.token);
      // @ts-ignore
      _this.socket.close();
      _this.isCloseBySelf = true;
      _this.pptt && clearTimeout(_this.pptt);
    }
  }
};

import SparkMD5 from 'spark-md5'


export const fileSparkMD5 = (file: any) => {
  let chunkSize = 5 * 1024 * 1024;
  return new Promise((resolve, reject) => {
    // @ts-ignore
    let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
    let chunks = Math.ceil(file.size / chunkSize);
    let currentChunk = 0;
    let spark = new SparkMD5.ArrayBuffer();
    let fileReader = new FileReader();
    fileReader.onload = function (e) {
      // @ts-ignore
      spark.append(e.target.result);
      currentChunk++;
      if (currentChunk < chunks) {
        loadNext();
      } else {
        let md5 = spark.end();
        resolve(md5);
      }
    };
    fileReader.onerror = function (e) {
      reject(e);
    };
    function loadNext() {
      let start = currentChunk * chunkSize;
      let end = start + chunkSize;
      if (end > file.size) {
        end = file.size;
      }
      fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }
    loadNext();
  });
}

export function arrayToMap(list: any[], idKey = 'id') {
  let ret: any = {}
  list.map(item => {
    ret[item[idKey]] = item;
  })
  return ret;
}


export function arrayToTree(list: any[], pid = '0', idKey = 'id', pidKey = 'pid', childrenKey = 'children') {
  return list.filter(item => item[pidKey] === pid).map(item => {
    let obj = { ...item };
    let cr = arrayToTree(list, item[idKey], idKey, pidKey, childrenKey);
    if (cr && cr.length) {
      obj[childrenKey] = cr;
    }
    return obj;
  });
}

export function treeToArray(tree: any[], childrenKey = 'children', newArray: any = []) {
  tree.forEach((item) => {
    let cr = item[childrenKey];
    if (cr) {
      delete item[childrenKey];
      if (cr.length) {
        newArray.push(item);
        return treeToArray(cr, childrenKey, newArray);
      }
    }
    newArray.push(item);
  });
  return newArray;
}

export function treeLevel(tree: any[], childrenKey = 'children', level = 2) {
  --level;
  tree.forEach((item) => {
    let cr = item[childrenKey];
    if (cr) {
      if (cr.length && level) {
        return treeLevel(cr, childrenKey, level);
      } else {
        delete item[childrenKey];
      }
    }
  });
  return tree;
}

export function findTreePath(lastId: string, map: any, newArray: any[] = []): any[] {
  let item: any = map[lastId];
  if (item) {
    if (item['parentCategoryId'] !== '0') {
      findTreePath(item['parentCategoryId'], map, newArray);
    }
    newArray.push(item);
  }
  return newArray;
}
